﻿// -----------------------------------------------------------------------
// <copyright file="Quad.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Assignment_3.Scene.Basic_Shapes
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Assignment_3.GenericStructures;
    using Assignment_3.Raytracer;
    using Assignment_3.Scene;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class Quad: Shape
    {
        Vector a,b,c,d;

        Vector normal;
        /// <summary>
        /// Enter the points in a counterclockwise format
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="c"></param>
        /// <param name="d"></param>


        public Quad(Vector a, Vector b, Vector c, Vector d)
        {
            this.a = a;
            this.b = b;
            this.c = c;
            this.d = d;

            this.normal = null;
        }

        public override Vector getFirstIntersection(Ray r)
        {
            //P = point
            //E = position of eye
            //d = direction of ray
            //t= distance from eye
            //N = normal 
            //a,b,c = vertices
            //x = |(P-A)|+|(P-B)|+ |(P dot C)|
            //if x > 1, you missed. x == 1, hit edge, x < 1, you hit
            //P = point 
            double t = -((r.origin - this.a).DotProduct(calculateNormal(null, r))) / (r.direction.DotProduct(calculateNormal(null, r)));

            Vector P = r.origin + t * r.direction;

            if (isOnside(r.origin, a, b, P) && isOnside(r.origin, b, c, P) && isOnside(r.origin, c, d, P) && isOnside(r.origin,d,a,P))
            {
                if (((r.origin - P) / r.direction).x > 0 || ((r.origin - P) / r.direction).y > 0 || ((r.origin - P) / r.direction).z > 0)
                {
                    return null;
                }
                return P;
            }
            else if (isOnside(r.origin, this.b, this.a, P) && isOnside(r.origin, this.c, this.b, P) && isOnside(r.origin, this.d, this.c, P) && isOnside(r.origin, this.a, this.d, P))
            {
                if (((r.origin - P) / r.direction).x > 0 || ((r.origin - P) / r.direction).y > 0 || ((r.origin - P) / r.direction).z > 0)
                {
                    return null;
                }
                return P;
            }
            else
            {
                return null;
            }

        }

        protected bool isOnside(Vector p0, Vector t1, Vector t2, Vector intersectionPoint)
        {
            bool result = true;

            Vector n1 = Vector.CrossProduct((p0 - t2), (p0 - t1));
            n1 /= n1.Length();

            double d1 = -p0.DotProduct(n1);

            if ((intersectionPoint.DotProduct(n1) + d1) < 0)
            {
                result = false;
            }

            return result;
        }

        public override Vector calculateNormal(Vector intersectionPoint, Ray r)
        {
            if (this.normal != null)
            {
                if (this.normal.DotProduct(r.direction) < 0)
                {
                    return this.normal;
                }
                else
                {
                    return new Vector(0, 0, 0) - this.normal;
                }
            }
            else
            {
                this.normal = Vector.CrossProduct((this.a - this.b), (this.a - this.c));

                this.normal /= this.normal.Length();

                if (this.normal.DotProduct(r.direction) < 0)
                {
                    return this.normal;
                }
                else
                {
                    return new Vector(0, 0, 0) - this.normal;
                }
            }

        }

        private bool PointIntersects(Vector intersectionPoint, Ray r)
        {
            double t = -((r.origin - this.a).DotProduct(this.normal)) / (r.direction.DotProduct(this.normal));

            Vector P = r.origin + t * r.direction;

            double x = (P - this.a).Length() + (P - this.b).Length() + (Vector.DotProduct(P, this.c));

            if (!intersectionPoint.equals(P))
            {
                return false;
            }
            else
            {
                if (isOnside(r.origin, this.a, this.b, P) && isOnside(r.origin, this.b, this.c, P) && isOnside(r.origin, this.c, this.d, P) && isOnside(r.origin, this.d, this.a, P))
                {
                    return true;
                }
                else if (isOnside(r.origin, this.b, this.a, P) && isOnside(r.origin, this.c, this.b, P) && isOnside(r.origin, this.d, this.c, P) && isOnside(r.origin, this.a, this.d, P))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        public override Ray getReflectedRay(Ray original, Vector intersectionPoint)
        {
            Ray reflectedRay = null;
            if (PointIntersects(intersectionPoint, original))
            {
                Vector normal = calculateNormal(intersectionPoint, original);
                double c1 = -Vector.DotProduct(normal, original.direction);
                reflectedRay = new Ray(intersectionPoint, original.direction + (2 * normal * c1));
                reflectedRay.direction /= reflectedRay.direction.Length();
            }

            return reflectedRay;
        }

        public override Ray getRefractedRay(Ray original, Vector intersectionPoint, double indexOfRefractionOutside = 1.00, double indexOfRefractionInside = 1.00)
        {
            if (this.properties.transparencyCoefficient < 1)
            {
                return new Ray(intersectionPoint, original.direction);
            }
            else
            {
                return null;
            }
        }
    }
}
